package com.tcm.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tcm.common.enums.CachePrefix;
import com.tcm.config.AppProperties;
import com.tcm.entity.BattleItem;
import com.tcm.entity.Book;
import com.tcm.entity.User;
import com.tcm.entity.bo.*;
import com.tcm.entity.dto.MessageDto;
import com.tcm.entity.dto.ScoreUpdateDto;
import com.tcm.entity.dto.param.BattleItemCorrectParam;
import com.tcm.entity.resp.Message;
import com.tcm.entity.vo.*;
import com.tcm.exception.BattleWsHandleException;
import com.tcm.service.*;
import com.tcm.utils.BattleMatchUtil;
import com.tcm.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author Guqier
 * @version 1.0
 * @date 2023/9/17 20:33
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BattleCoreServiceImpl implements BattleCoreService {

    private final BattleMatchUtil battleMatchUtil;

    private final RedisUtil redisUtil;

    private final UserService userService;

    private final ImageService imageService;

    private final BookService bookService;

    private final BattleItemService battleItemService;

    private final BattleService battleService;

    private final ScoreService scoreService;

    private final LearningTimeService learningTimeService;

    /**
     * 开始匹配
     * @param userId 用户ID
     * @return 消息封装类
     */
    @Override
    public List<MessageDto> startMatch(Long userId) {
        // 获取当前用户信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(userId.toString()));
        // 获取用户缓存信息
        BattleUserCacheBo userInfo = battleMatchUtil.getMatchUserInfo(userId.toString());
        if (Objects.nonNull(userInfo) && userInfo.getStatus().equals(0)) {// 不为空则已有信息，则响应已有匹配信息
            return null;
        }
        // 创建用户信息并存入缓存
        userInfo = this.initUserInfo(userId, userCacheBo.getAccount());
        battleMatchUtil.setMatchUserInfo(userId.toString(), userInfo);
        // 将用户加入匹配队列
        battleMatchUtil.pushToMatchQueue(userId.toString());
        return checkMatchCondition(userId);
    }

    /**
     * 检查匹配情况
     * @return 消息发送Dto
     */
    private List<MessageDto> checkMatchCondition(Long userId) {
        if (battleMatchUtil.getMatchQueueSize() >= 2) {// 如果队列数量大于或等于2则将队列头部两个用户建立匹配关系
            // 获取用户ID
            List<String> userIds = new ArrayList<>();
            for (int i = 0; i < 2; i++) {
                userIds.add(battleMatchUtil.popFromMatchQueue());
            }
            // 获取用户信息
            List<BattleUserCacheBo> userCacheBos = new ArrayList<>();
            userIds.stream().distinct().forEach(id -> userCacheBos.add(battleMatchUtil.getMatchUserInfo(id)));
            // 如果有用户退出匹配则将剩余用户重新放回匹配队列
            if (userCacheBos.size() != 2) {
                userCacheBos.forEach(bo -> battleMatchUtil.pushToMatchQueue(bo.getUserId().toString()));
                return null;
            }

            // 创建房间
            Long roomId = createRoom(2, userCacheBos, 1, userId);
            // 更新用户信息
            for (BattleUserCacheBo userCacheBo : userCacheBos) {
                userCacheBo.setRoomId(roomId);
                userCacheBo.setStatus(1);
                userCacheBo.setConsumeTime(0);
                userCacheBo.setIsMatch(Boolean.TRUE);
                battleMatchUtil.setMatchUserInfo(userCacheBo.getUserId().toString(), userCacheBo);
            }
            // 响应匹配信息
            List<User> users = userCacheBos.stream().map(battleUserCacheBo -> userService.getById(battleUserCacheBo.getUserId())).collect(Collectors.toList());
            System.out.println(users);
            List<BattleMatchUserMsg> userMsgs = users.stream().map(user -> new BattleMatchUserMsg()
                    .setNickname(user.getNickname())
                    .setAvatarUrl(Optional.ofNullable(user.getAvatar()).isPresent()
                            ? imageService.getImageById(user.getAvatar()).getRemoteFileUrl()
                            : null)
                    .setUserId(user.getId())).collect(Collectors.toList());
            return users.stream().map(user -> {
                ArrayList<BattleMatchUserMsg> list = new ArrayList<BattleMatchUserMsg>() {{
                    addAll(userMsgs);
                }};
                if (!list.get(0).getUserId().equals(user.getId())) {
                    Collections.reverse(list);
                }

                return new MessageDto()
                        .setUserId(user.getId())
                        .setMessage(new Message()
                                .setCode(AppProperties.BattleMsgCode.START_MATCH)
                                .setMsg("匹配成功")
                                .setData(list));
            }).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 创建房间
     * @param maxNum 房间最大人数，仅限2、4、6、8
     * @return 房间ID
     */
    private Long createRoom(Integer maxNum, List<BattleUserCacheBo> userCacheBos, Integer status, Long creatorId) {
        // 房间人数仅限2、4、6、8人
        if (maxNum % 2 != 0 || maxNum > 8 || maxNum < 2) {
            return null;
        }
        long roomId = IdUtil.getSnowflakeNextId();
        BattleRoomCacheBo roomCacheBo = new BattleRoomCacheBo();
        roomCacheBo
                .setRoomId(roomId)
                .setMaxNum(maxNum)
                .setStatus(status)
                .setCreatorId(creatorId)
                .setBattleId(IdUtil.getSnowflakeNextId())
                .setMembers(userCacheBos.stream().map(battleUserCacheBo -> new BattleRoomCacheBo.Member(battleUserCacheBo.getUserId(),
                        battleUserCacheBo.getAccount(),
                        0,
                        0,
                        new ArrayList<>(),
                        false,
                        false)).collect(Collectors.toList()));
        battleMatchUtil.setRoomInfo(String.valueOf(roomId), roomCacheBo);
        return roomId;
    }

    /**
     * 初始化用户信息
     * @param account 账号
     * @return 用户信息类
     */
    private BattleUserCacheBo initUserInfo(Long userId, String account) {
        return new BattleUserCacheBo()
                .setUserId(userId)
                .setAccount(account)
                .setStatus(0)
                .setIsMatch(Boolean.FALSE)
                .setScore(0)
                .setConsumeTime(0)
                .setRoomId(null)
                .setTopics(new ArrayList<>());
    }

    /**
     * 获取题目
     * @param userId   用户ID
     * @param courseId 课程ID
     * @return 题目响应数据
     */
    @Override
    public BattleTopicResp getTopic(Long userId, Long courseId) {
        // 获取用户匹配信息
        BattleUserCacheBo matchUserInfo = battleMatchUtil.getMatchUserInfo(String.valueOf(userId));
        if (Objects.isNull(matchUserInfo)) {
            throw new BattleWsHandleException(userId, "匹配信息不存在或已过期");
        }
        // 获取已选题目
        List<BattleTopicBo> topics = matchUserInfo.getTopics();
        List<BattleTopicBo> resps = new ArrayList<>(topics);
        BattleItem battleItem = getBattleTopicRandom(resps, courseId);
        matchUserInfo.setTopics(resps);
        battleMatchUtil.setMatchUserInfo(String.valueOf(userId), matchUserInfo);
        return battleItemService.transferBattleItemToTopicResp(battleItem);
    }

    /**
     * 随机选择题目
     * @param resps    题目列表
     * @param courseId 课程ID
     * @return 题目信息
     */
    private BattleItem getBattleTopicRandom(List<BattleTopicBo> resps, Long courseId) {
        // 获取当前课程下所有书籍节点
        List<Book> books = bookService.getChildBooks(courseId);
        List<Long> bookIds = books.stream().map(Book::getId).collect(Collectors.toList());

        // 检索题目
        LambdaQueryWrapper<BattleItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(!CollectionUtils.isEmpty(books), BattleItem::getChapterId, bookIds);
        queryWrapper.apply(CollectionUtils.isEmpty(books), "1 != 1");
        int count = battleItemService.count(queryWrapper);
        Random random = new Random();
        List<Long> ids = resps.stream().map(BattleTopicBo::getId).collect(Collectors.toList());
        while (true) {
            int i = random.nextInt(count);
            BattleItem battleItem = battleItemService.getOne(new LambdaQueryWrapper<BattleItem>()
                    .in(!CollectionUtils.isEmpty(books), BattleItem::getChapterId, bookIds)
                    .apply(CollectionUtils.isEmpty(books), "1 != 1")
                    .last(String.format("LIMIT %d, 1", i)));
            if (!ids.contains(battleItem.getId())) {
                BattleTopicBo battleTopicBo = new BattleTopicBo();
                battleTopicBo.setId(battleItem.getId());
                battleTopicBo.setType(battleItem.getType());
                battleTopicBo.setScore(0);
                battleTopicBo.setAns("");
                battleTopicBo.setIsMultiple(battleItemService.isMultiple(battleItem.getId()));
                resps.add(battleTopicBo);
                return battleItem;
            }
        }
    }

    /**
     * 批改题目
     * @param param  题目批改参数
     * @param userId 用户ID
     */
    @Override
    public List<MessageDto> correctTopic(BattleItemCorrectParam param, Long userId) {
        // 获取用户信息
        BattleUserCacheBo matchUserInfo = battleMatchUtil.getMatchUserInfo(String.valueOf(userId));
        if (Objects.isNull(matchUserInfo)) {
            throw new BattleWsHandleException(userId, "匹配信息不存在或已过期");
        }
        // 批改题目并获得分数
        BattleItemCorrectResp correctResp = battleItemService.correctBattleItem(param.getId(), param.getAns());
        Integer score = correctResp.getScore();
        // 获取题目信息
        BattleItem battleItem = battleItemService.getBattleItemById(param.getId());
        correctResp.setItemId(battleItem.getId().toString());
        correctResp.setContent(battleItem.getContent() + (StringUtils.hasText(battleItem.getSubContent()) ? "\n" + battleItem.getSubContent() : ""));

        // 更新用户匹配缓存信息
        List<BattleTopicBo> topics = matchUserInfo.getTopics();
        List<BattleTopicBo> collect = topics.stream().map(battleTopicBo -> {
            BattleTopicBo bo = new BattleTopicBo();
            BeanUtils.copyProperties(battleTopicBo, bo);
            if (bo.getId().equals(param.getId())) {
                bo.setScore(score);
                bo.setAns(param.getAns());
            }
            return bo;
        }).collect(Collectors.toList());
        matchUserInfo.setScore(matchUserInfo.getScore() + score);
        matchUserInfo.setConsumeTime((matchUserInfo.getConsumeTime() != null ? matchUserInfo.getConsumeTime() : 0)
                + (param.getSeconds() != null ? param.getSeconds() : 0));
        matchUserInfo.setTopics(collect);
        correctResp.setTotalScore(matchUserInfo.getScore());
        // 判断是否完成
        boolean flag = matchUserInfo.getScore() >= 100;
        // 保存用户信息
        if (flag){
            matchUserInfo.setStatus(3);// 状态为结束
        }
        battleMatchUtil.setMatchUserInfo(String.valueOf(userId), matchUserInfo);

        // 更新房间信息
        if (flag) {
            // 获取房间信息
            BattleRoomCacheBo room = battleMatchUtil.getRoomInfo(String.valueOf(matchUserInfo.getRoomId()));
            if (Objects.isNull(room)) {
                throw new BattleWsHandleException(userId, "房间信息不存在或已过期");
            }
            // 更新房间中信息
            List<BattleRoomCacheBo.Member> list = room.getMembers().stream().peek(member -> {
                if (member.getUserId().equals(userId)) {
                    member.setScore(matchUserInfo.getScore());
                    member.setConsumeTime(matchUserInfo.getConsumeTime());
                    member.setTopics(matchUserInfo.getTopics());
                    member.setIsFinished(true);
                }
            }).collect(Collectors.toList());
            room.setMembers(list);
            battleMatchUtil.setRoomInfo(String.valueOf(room.getRoomId()), room);

            // 保存匹配信息到数据库
            this.saveBattleAsync(matchUserInfo, room, true);

            // 保存积分信息
            this.saveScoreAsync(matchUserInfo.getAccount(), matchUserInfo.getUserId(), matchUserInfo.getScore());

            // 保存学习时长
            this.saveLearningTimeAsync(matchUserInfo.getConsumeTime(), matchUserInfo.getUserId());
        }

        // 构建响应消息
        List<MessageDto> messageDtoList = new ArrayList<>();
        Message correctMessage = new Message().setCode(AppProperties.BattleMsgCode.CORRECT).setMsg("success").setData(correctResp);
        messageDtoList.add(new MessageDto().setMessage(correctMessage).setUserId(userId));
        if (flag) {
            Message finished = new Message().setCode(AppProperties.BattleMsgCode.FINISHED).setMsg("finished");
            messageDtoList.add(new MessageDto().setMessage(finished).setUserId(userId));
        }
        return messageDtoList;
    }

    /**
     * 异步保存对战记录
     * @param userCacheBo 用户缓存
     * @param roomCacheBo 房间缓存
     * @param isComplete 是否完成
     */
    @Async
    public void saveBattleAsync(BattleUserCacheBo userCacheBo, BattleRoomCacheBo roomCacheBo, Boolean isComplete){
        battleService.saveBattle(userCacheBo, roomCacheBo, isComplete);
    }

    /**
     * 保存学生积分信息
     * @param account 学生账号
     * @param score 得分
     */
    @Async
    public void saveScoreAsync(String account, Long userId, Integer score){
        ScoreUpdateDto scoreUpdateDto = new ScoreUpdateDto();
        scoreUpdateDto.setNum(score);
        scoreUpdateDto.setAccount(account);
        scoreUpdateDto.setType(3);
        scoreService.saveScore(scoreUpdateDto, userId);
    }

    /**
     * 保存学习时长
     * @param seconds 时长
     * @param userId 用户ID
     */
    @Async
    public void saveLearningTimeAsync(Integer seconds, Long userId){
        learningTimeService.saveStuLearningTime(seconds, userId);
    }

    /**
     * 获取对战详细
     * @param userId 用户ID
     * @return 对战详细列表
     */
    @Override
    public List<MessageDto> getBattleDetail(Long userId) {
        // 获取用户信息
        BattleUserCacheBo matchUserInfo = battleMatchUtil.getMatchUserInfo(String.valueOf(userId));
        if (Objects.isNull(matchUserInfo)) {
            throw new BattleWsHandleException(userId, "对战信息不存在或已过期");
        }
        // 获取房间信息
        BattleRoomCacheBo room = battleMatchUtil.getRoomInfo(String.valueOf(matchUserInfo.getRoomId()));
        if (Objects.isNull(room)) {
            throw new BattleWsHandleException(userId, "房间信息不存在或已过期");
        }
        List<BattleRoomCacheBo.Member> members = room.getMembers();
        List<BattleDetailResp> collect = members.stream().map(member -> {
            User user = userService.getUserByAccount(member.getAccount());
            BattleDetailResp resp = new BattleDetailResp();
            resp.setNickname(user.getNickname());
            resp.setIsExit(member.getIsExit());
            resp.setIsFinished(member.getIsFinished());
            resp.setUserId(String.valueOf(member.getUserId()));
            resp.setAccount(member.getAccount());
            resp.setScore(member.getScore());
            resp.setSeconds(member.getConsumeTime());
            List<BattleTopicBo> topics = member.getTopics();
            resp.setTotalNum(topics.size());
            resp.setCorrectNum(new Long(topics.stream().filter(t -> t.getScore().equals(AppProperties.BATTLE_ITEM_SCORE)).count()).intValue());
            if (user.getAvatar() != null) {
                resp.setAvatarUrl(imageService.getImageById(user.getAvatar()).getRemoteFileUrl());
            }
            return resp;
        }).collect(Collectors.toList());
        List<BattleDetailResp> list = collect.stream().filter(BattleDetailResp::getIsFinished).sorted((Comparator.comparing(BattleDetailResp::getSeconds))).collect(Collectors.toList());
        List<BattleDetailResp> unfinished = collect.stream().filter(resp -> !resp.getIsFinished()).collect(Collectors.toList());
        list.addAll(unfinished);
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setRank(i + 1);
        }

        // 封装响应数据，房间内所有用户
        return members.stream().map(member -> new MessageDto().setUserId(member.getUserId()).setMessage(
                new Message().setCode(AppProperties.BattleMsgCode.DETAIL).setMsg("success").setData(list))).collect(Collectors.toList());
    }

    /**
     * 获取题目解析
     * @param userId 用户ID
     * @return 题目解析集合
     */
    @Override
    public List<BattleItemDescribeResp> getDescribes(Long userId) {
        // 获取用户信息
        BattleUserCacheBo matchUserInfo = battleMatchUtil.getMatchUserInfo(String.valueOf(userId));
        if (Objects.isNull(matchUserInfo)) {
            throw new BattleWsHandleException(userId, "匹配信息不存在或已过期");
        }
        // 获取所有题目
        List<BattleTopicBo> topics = matchUserInfo.getTopics();
        List<Long> ids = topics.stream().map(BattleTopicBo::getId).collect(Collectors.toList());
        // 获取对战题目信息
        List<BattleItem> battleItems = battleItemService.list(new LambdaQueryWrapper<BattleItem>()
                .in(!CollectionUtils.isEmpty(ids), BattleItem::getId, ids)
                .apply(CollectionUtils.isEmpty(ids), "1 != 1"));
        return battleItemService.transferBattleItemToDescribeResp(battleItems);
    }

    /**
     * 退出匹配
     * @param userId 用户ID
     * @return 退出结果
     */
    @Override
    public Boolean exitMatch(Long userId){
        return battleMatchUtil.deleteMatchUserInfo(String.valueOf(userId));
    }

    /**
     * 创建邀请对战房间
     * @param userId 用户ID
     * @param maxNum 房间最大人数
     * @return 对战房间ID
     */
    @Override
    public Map<String, String> createBattleRoom(Long userId, Integer maxNum) {
        // 获取当前用户信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(userId.toString()));

        // 创建用户信息并存入缓存
        BattleUserCacheBo userInfo = this.initUserInfo(userId, userCacheBo.getAccount());

        // 创建房间
        Long roomId = this.createRoom(maxNum, new ArrayList<BattleUserCacheBo>() {{
            add(userInfo);
        }}, 0, userId);
        // 创建失败则响应失败信息
        if (Objects.isNull(roomId)) {
            throw new BattleWsHandleException(userId, "房间最大人数仅可以为2、4、6、8");
        }
        userInfo.setRoomId(roomId);
        battleMatchUtil.setMatchUserInfo(userId.toString(), userInfo);

        // 封装响应信息
        return new HashMap<String, String>(){{
            put("roomId", String.valueOf(roomId));
        }};
    }

    /**
     * 获取房间邀请码
     * @param roomId 房间ID
     * @param userId 用户ID
     * @return 邀请码
     */
    @Override
    public Map<String, String> getRoomInvitationCode(Long roomId, Long userId){
        // 获取房间信息
        BattleRoomCacheBo roomInfo = battleMatchUtil.getRoomInfo(String.valueOf(roomId));
        if (Objects.isNull(roomInfo) || !roomInfo.getStatus().equals(0)) {
            throw new BattleWsHandleException(userId, "房间不存在或对战已开始");
        }

        // 创建邀请码
        String code = IdUtil.simpleUUID();
        BattleRoomInviteBo bo = new BattleRoomInviteBo();
        bo.setRoomId(roomInfo.getRoomId());
        // 保存邀请信息到缓存
        redisUtil.setCacheObject(CachePrefix.BATTLE_ROOM_INVITATION_CODE.getCacheKey(String.valueOf(code)), bo, 5, TimeUnit.MINUTES);
        return new HashMap<String, String>(){{
            put("code", code);
        }};
    }

    /**
     * 加入房间
     * @param userId 用户ID
     * @param code 邀请码
     * @return 加入结果
     */
    @Override
    public List<MessageDto> joinRoom(Long userId, String code){
        // 获取邀请信息
        BattleRoomInviteBo room = redisUtil.getCacheObject(CachePrefix.BATTLE_ROOM_INVITATION_CODE.getCacheKey(String.valueOf(code)));
        if (Objects.isNull(room)){
            throw new BattleWsHandleException(userId, "邀请信息不存在或已过期");
        }
        // 获取房间信息
        BattleRoomCacheBo roomInfo = battleMatchUtil.getRoomInfo(String.valueOf(room.getRoomId()));
        if (Objects.isNull(roomInfo) || !roomInfo.getStatus().equals(0)) {
            throw new BattleWsHandleException(userId, "房间不存在或对战已开始");
        }

        // 获取当前用户信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(userId.toString()));
        // 创建用户信息并存入缓存
        BattleUserCacheBo userInfo = this.initUserInfo(userId, userCacheBo.getAccount());
        userInfo.setRoomId(roomInfo.getRoomId());
        battleMatchUtil.setMatchUserInfo(userId.toString(), userInfo);

        // 用户加入房间
        List<BattleRoomCacheBo.Member> members = roomInfo.getMembers();
        List<BattleRoomCacheBo.Member> memberList = new ArrayList<>(members);
        memberList.add(new BattleRoomCacheBo.Member(userId, userCacheBo.getAccount(), 0, 0, new ArrayList<>(), false, false));
        roomInfo.setMembers(memberList);
        battleMatchUtil.setRoomInfo(String.valueOf(roomInfo.getRoomId()), roomInfo);

        // 通知所有房间中的用户
        return memberList.stream().map(member -> {
            BattleRoomInfoResp info = this.getRoomInfo(member.getUserId());
            Message message = new Message().setCode(AppProperties.BattleMsgCode.ROOM_INFO).setMsg("房间信息更新").setData(info);
            return new MessageDto().setUserId(member.getUserId()).setMessage(message);
        }).collect(Collectors.toList());
    }

    /**
     * 开始房间对战
     * @param userId 用户ID
     * @return 消息Dto
     */
    @Override
    public List<MessageDto> startRoomBattle(Long userId){
        // 获取用户信息
        BattleUserCacheBo matchUserInfo = battleMatchUtil.getMatchUserInfo(String.valueOf(userId));
        if (Objects.isNull(matchUserInfo) || Objects.isNull(matchUserInfo.getRoomId())) {
            throw new BattleWsHandleException(userId, "未加入任何房间");
        }
        // 获取房间信息
        BattleRoomCacheBo room = battleMatchUtil.getRoomInfo(String.valueOf(matchUserInfo.getRoomId()));
        if (Objects.isNull(room)) {
            throw new BattleWsHandleException(userId, "房间信息不存在或已过期");
        }
        if (!room.getCreatorId().equals(userId)) {
            throw new BattleWsHandleException(userId, "仅房主可以开始对战");
        }

        // 保存信息到缓存
        matchUserInfo.setStatus(1);
        room.setStatus(1);
        battleMatchUtil.setMatchUserInfo(String.valueOf(userId), matchUserInfo);
        battleMatchUtil.setRoomInfo(String.valueOf(room.getRoomId()), room);

        // 通知所有人可以开始对战
        List<BattleRoomCacheBo.Member> members = room.getMembers();
        return members.stream().map(member -> new MessageDto().setUserId(member.getUserId()).setMessage(
                new Message()
                        .setCode(AppProperties.BattleMsgCode.START)
                        .setMsg("开始对战")
        )).collect(Collectors.toList());
    }

    /**
     * 获取房间信息
     * @param userId 当前用户ID
     * @return 房间信息
     */
    @Override
    public BattleRoomInfoResp getRoomInfo(Long userId){
        // 获取用户信息
        BattleUserCacheBo matchUserInfo = battleMatchUtil.getMatchUserInfo(String.valueOf(userId));
        if (Objects.isNull(matchUserInfo) || Objects.isNull(matchUserInfo.getRoomId())) {
            throw new BattleWsHandleException(userId, "未加入任何房间");
        }
        // 获取房间信息
        BattleRoomCacheBo room = battleMatchUtil.getRoomInfo(String.valueOf(matchUserInfo.getRoomId()));
        if (Objects.isNull(room)) {
            throw new BattleWsHandleException(userId, "房间信息不存在或已过期");
        }
        // 构造成员列表
        return this.buildRoomInfoResp(room);
    }

    /**
     * 退出PK对战
     * @param userId 用户ID
     * @return 消息集合
     */
    @Override
    public List<MessageDto> exit(Long userId){
        // 获取用户信息
        BattleUserCacheBo matchUserInfo = battleMatchUtil.getMatchUserInfo(String.valueOf(userId));
        if (Objects.isNull(matchUserInfo)) {// 如果用户信息不存在则退出
            return null;
        }
        // 从匹配队列中移除
        battleMatchUtil.removeFromMatchQueue(String.valueOf(userId));
        // 获取房间信息并更新
        Long roomId = matchUserInfo.getRoomId();
        if (Objects.nonNull(roomId)){
            BattleRoomCacheBo room = battleMatchUtil.getRoomInfo(String.valueOf(matchUserInfo.getRoomId()));
            if (Objects.nonNull(room)){
                if (room.getStatus().equals(0)){
                    // 如果房间还未开始pk则直接退出
                    if (room.getCreatorId().equals(matchUserInfo.getUserId())){
                        List<MessageDto> messageDtos = this.broadCastRoomDestroy(roomId);
                        // 如果是房主则解散房间
                        List<BattleRoomCacheBo.Member> members = room.getMembers();
                        members.forEach(member -> battleMatchUtil.deleteMatchUserInfo(String.valueOf(member.getUserId())));
                        battleMatchUtil.deleteRoomInfo(String.valueOf(roomId));
                        return messageDtos;
                    }else {
                        // 不是房主则退出房间
                        List<BattleRoomCacheBo.Member> members = room.getMembers();
                        List<BattleRoomCacheBo.Member> collect = members.stream().filter(member -> !member.getUserId().equals(matchUserInfo.getUserId())).collect(Collectors.toList());
                        room.setMembers(collect);
                        battleMatchUtil.setRoomInfo(String.valueOf(room.getRoomId()), room);
                        return this.broadCastRoomInfo(roomId);
                    }
                }else {
                    // 如果房间已开始则标记已离开
                    List<BattleRoomCacheBo.Member> members = room.getMembers();
                    if (members.size() > 1){
                        List<BattleRoomCacheBo.Member> collect = new ArrayList<>(members);
                        for (BattleRoomCacheBo.Member member : collect) {
                            if (member.getUserId().equals(userId) && !member.getIsFinished()) {
                                member.setScore(0);
                                member.setConsumeTime(9966);
                                member.setTopics(matchUserInfo.getTopics());
                                member.setIsFinished(false);
                                member.setIsExit(true);
                            }
                        }
                        this.saveBattleAsync(matchUserInfo, room, false);
                        battleMatchUtil.setRoomInfo(String.valueOf(room.getRoomId()), room);
                    }else {
                        battleMatchUtil.deleteRoomInfo(String.valueOf(room.getRoomId()));
                    }
                }
            }
        }

        // 删除用户信息
        battleMatchUtil.deleteMatchUserInfo(String.valueOf(userId));
        return null;
    }

    /**
     * 广播房间信息
     * @param roomId 房间ID
     * @return 消息集合
     */
    private List<MessageDto> broadCastRoomInfo(Long roomId){
        BattleRoomCacheBo room = battleMatchUtil.getRoomInfo(String.valueOf(roomId));
        if (Objects.isNull(room)) {
            return null;
        }

        // 构造成员列表
        List<BattleRoomCacheBo.Member> members = room.getMembers();
        BattleRoomInfoResp resp = this.buildRoomInfoResp(room);

        // 构造消息集
        return members.stream().map(member -> new MessageDto().setUserId(member.getUserId()).setMessage(
                new Message()
                        .setCode(AppProperties.BattleMsgCode.ROOM_INFO)
                        .setMsg("房间信息")
                        .setData(resp)
        )).collect(Collectors.toList());
    }

    /**
     * 广播房间销毁
     * @param roomId 房间ID
     * @return 消息集合
     */
    private List<MessageDto> broadCastRoomDestroy(Long roomId){
        BattleRoomCacheBo room = battleMatchUtil.getRoomInfo(String.valueOf(roomId));
        if (Objects.isNull(room)) {
            return null;
        }

        // 获取成员列表
        List<BattleRoomCacheBo.Member> members = room.getMembers();
        return members.stream().map(member -> new MessageDto().setUserId(member.getUserId()).setMessage(
                        new Message()
                                .setCode(AppProperties.BattleMsgCode.ROOM_DESTROY)
                                .setMsg("房间已被解散")
                )
        ).collect(Collectors.toList());
    }

    /**
     * 构建房间信息响应封装类
     * @param room 房间缓存信息
     * @return 响应封装类
     */
    private BattleRoomInfoResp buildRoomInfoResp(BattleRoomCacheBo room){
        List<BattleRoomCacheBo.Member> members = room.getMembers();
        List<BattleRoomInfoResp.Member> memberList = members.stream().map(member -> {
            User user = userService.getUserByAccount(member.getAccount());
            BattleRoomInfoResp.Member m = new BattleRoomInfoResp.Member();
            m.setUserId(String.valueOf(member.getUserId()));
            m.setAccount(member.getAccount());
            m.setNickname(user.getNickname());
            Optional.ofNullable(user.getAvatar()).ifPresent(id -> m.setAvatarUrl(imageService.getImageById(id).getRemoteFileUrl()));
            // 获取对战场次和最短耗时
            Map<String, Integer> resMap = battleService.getBattleCountAndMinConsumeTime(user.getAccount());
            m.setBattleCount(resMap.get("count"));
            m.setMinSeconds(resMap.get("minConsumeTime"));
            return m;
        }).collect(Collectors.toList());
        // 构造结果集
        BattleRoomInfoResp resp = new BattleRoomInfoResp();
        resp.setRoomId(String.valueOf(room.getRoomId()));
        resp.setMaxNum(room.getMaxNum());
        resp.setCreatorId(String.valueOf(room.getCreatorId()));
        resp.setMembers(memberList);
        return resp;
    }
}
